﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.IO;
using System.Diagnostics;

using Pg.BioMedics.SDR.Client.Security;
using Pg.BioMedics.SDR.Client.Multimedia;
using Pg.BioMedics.SDR.Client.OperationalWebService;

namespace Pg.BioMedics.SDR.Client
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Constants

        private const string RefreshDocumentsBackgroundWorker = "refreshDocumentsBackgroundWorker";
        private const string RegisterDocumentBackgroundWorker = "registerDocumentBackgroundWorker";
        private const string ExecuteSpokenQueryBackgroundWorker = "executeSpokenQueryBackgroundWorker";
        private const string OpenDocumentBackgroundWorker = "openDocumentBackgroundWorker";

        #endregion

        #region Fields

        private Credentials credentials;
        private VoiceRecorder recorder;
        private DisposableFiles disposableFiles = new DisposableFiles();

        #endregion

        #region Initialization methods

        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region Event handlers

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                // get username and password
                LoginWindow loginWindow = new LoginWindow();
                bool? result = loginWindow.ShowDialog();
                if (!result.HasValue)
                    App.Current.Shutdown(0);
                else if (!result.Value)
                    App.Current.Shutdown(0);

                this.credentials = loginWindow.Credentials;                                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ExecuteQueryButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //execute query
                using (OperationalWebServiceClient client = new OperationalWebServiceClient())
                {
                    client.ClientCredentials.UserName.UserName = this.credentials.UserName;
                    client.ClientCredentials.UserName.Password = this.credentials.Password;

                    queryResultsListView.DataContext = from searchResult in client.ExecuteTextQuery(queryTextBox.Text)
                                                       let document = client.GetDocument(searchResult)
                                                       select new
                                                       {
                                                           RelevanceScore = searchResult.RelevanceScore,
                                                           Id = document.Id,
                                                           Title = document.Title,
                                                           Description = document.Description,
                                                           TypeCode = document.TypeCode,
                                                           ContentId = document.ContentId,
                                                           LanguageCode = document.LanguageCode,
                                                           CreationDate = document.StatusDate,
                                                           Author = document.StatusAuthorLogin
                                                       };
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage == 0)
                ProgressWindow.Show();
            else if (e.ProgressPercentage == 100)
                ProgressWindow.Hide();
        }

        #endregion  
        
        #region Command methods

        #region Refresh documents

        private void RefreshDocumentsCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            BackgroundWorker worker = Resources[RefreshDocumentsBackgroundWorker] as BackgroundWorker;
            worker.RunWorkerAsync();
        }

        private void RefreshDocumentsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // get instances
            BackgroundWorker worker = sender as BackgroundWorker;

            // retrive documents
            worker.ReportProgress(0);
            using (OperationalWebServiceClient client = new OperationalWebServiceClient())
            {
                client.ClientCredentials.UserName.UserName = this.credentials.UserName;
                client.ClientCredentials.UserName.Password = this.credentials.Password;

                e.Result = client.GetDocuments();                 
            }
            worker.ReportProgress(100);
        }        

        private void RefreshDocumentsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                ProgressWindow.Hide();
                return;
            }

            documentsListView.DataContext = e.Result;
        }
        
        #endregion        

        #region Register document

        private void RegisterDocumentCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            // get document and content
            RegisterDocumentWindow registerDocumentWindow = new RegisterDocumentWindow();
            bool? result = registerDocumentWindow.ShowDialog();
            if (!result.HasValue)
                return;
            else if (!result.Value)
                return;

            // execute operations in the background
            BackgroundWorker worker = Resources[RegisterDocumentBackgroundWorker] as BackgroundWorker;
            worker.RunWorkerAsync(new object[] { registerDocumentWindow.Document,
                                                 registerDocumentWindow.Content });
        }

        private void RegisterDocumentBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // get instances
            BackgroundWorker worker = sender as BackgroundWorker;
            Document document = ((object[])e.Argument).First() as Document;
            Content content = ((object[])e.Argument).Last() as Content;

            // read file
            worker.ReportProgress(0);
            content.Data = File.ReadAllBytes(content.FileName);

            // upload data
            worker.ReportProgress(50);
            using (OperationalWebServiceClient client = new OperationalWebServiceClient())
            {
                client.ClientCredentials.UserName.UserName = this.credentials.UserName;
                client.ClientCredentials.UserName.Password = this.credentials.Password;

                client.RegisterDocument(document, content);
                e.Result = client.GetDocuments(); 
            }
            worker.ReportProgress(100);
        }

        private void RegisterDocumentBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                ProgressWindow.Hide();
                return;
            }

            documentsListView.DataContext = e.Result;
        }

        #endregion

        #region Record spoken query

        private void RecordSpokenQueryCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (this.recorder == null);
        }

        private void RecordSpokenQueryCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            try
            {
                this.recorder = new VoiceRecorder();
                this.recorder.Record();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region Execute spoken query

        private void ExecuteSpokenQueryCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.recorder == null)
                e.CanExecute = false;
            else
                e.CanExecute = this.recorder.Recording;
        }

        private void ExecuteSpokenQueryCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.recorder.Stop();

            BackgroundWorker worker = Resources[ExecuteSpokenQueryBackgroundWorker] as BackgroundWorker;
            worker.RunWorkerAsync(this.recorder.RecorderBytes);         
        }

        private void ExecuteSpokenQueryBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // extract parameters
            byte[] audioData = e.Argument as byte[];

            //execute query
            using (OperationalWebServiceClient client = new OperationalWebServiceClient())
            {
                client.ClientCredentials.UserName.UserName = this.credentials.UserName;
                client.ClientCredentials.UserName.Password = this.credentials.Password;
                
                e.Result = (from searchResult in client.ExecuteSpokenQuery(audioData, -1)
                            let document = client.GetDocument(searchResult)
                            select new
                            {
                                RelevanceScore = searchResult.RelevanceScore,
                                Id = document.Id,
                                Title = document.Title,
                                Description = document.Description,
                                TypeCode = document.TypeCode,
                                ContentId = document.ContentId,
                                LanguageCode = document.LanguageCode,
                                CreationDate = document.StatusDate,
                                Author = document.StatusAuthorLogin
                            }).ToList();
            }
        }

        private void ExecuteSpokenQueryBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                ProgressWindow.Hide();
                return;
            }

            queryResultsListView.DataContext = e.Result;

            if (this.recorder != null)
            {
                this.recorder.Dispose();
                this.recorder = null;
            }
        }

        #endregion

        #region Play spoken query

        private void PlaySpokenQueryCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.recorder == null)
                e.CanExecute = false;
            else
                e.CanExecute = this.recorder.Recording;
        }

        private void PlaySpokenQueryCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.recorder.Play();

            if (this.recorder != null)
            {
                this.recorder.Dispose();
                this.recorder = null;
            }
        }

        #endregion

        #region Open document

        private void OpenDocumentCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (e.Parameter != null);
        }

        private void OpenDocumentCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            BackgroundWorker worker = Resources[OpenDocumentBackgroundWorker] as BackgroundWorker;
            worker.RunWorkerAsync(e.Parameter);
        }

        private void OpenDocumentBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // get instances
            BackgroundWorker worker = sender as BackgroundWorker;
            Document document = e.Argument as Document;            

            // download file
            worker.ReportProgress(0);            
            using (OperationalWebServiceClient client = new OperationalWebServiceClient())
            {
                client.ClientCredentials.UserName.UserName = this.credentials.UserName;
                client.ClientCredentials.UserName.Password = this.credentials.Password;

                Content content = client.GetContent(document);
                string tempFile = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetFileName(content.FileName));
                File.WriteAllBytes(tempFile, content.Data);

                e.Result = tempFile;
            }
            worker.ReportProgress(100);
        }

        private void OpenDocumentBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                ProgressWindow.Hide();
                return;
            }

            string tempFile = e.Result as string;

            this.disposableFiles.Add(tempFile);
            Process.Start(tempFile);
        }

        #endregion        

        #region Show document details

        private void ShowDocumentDetailsCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (e.Parameter != null);
        }

        private void ShowDocumentDetailsCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {

        }
        
        #endregion

        #region Open result document
        
        #endregion

        #endregion
    }
}
